import { Logger, Module } from "@nestjs/common";
import { ConfigModule, ConfigService } from "@nestjs/config";
import { APP_GUARD } from "@nestjs/core";
import { ScheduleModule } from "@nestjs/schedule";
import { ServeStaticModule } from "@nestjs/serve-static";
import { ThrottlerGuard, ThrottlerModule } from "@nestjs/throttler";
import * as fs from "fs";
import { join } from "path";

import { AppController } from "./app.controller";
import { AppService } from "./app.service";
import {
    STATIC_ADMIN_DIR,
    STATIC_ASSETS_CLIENT_ROOT_DIR,
    STATIC_MOBILE_DIR,
    STATIC_PC_DIR
} from "./core/config/config-data";
import { CoreModule } from "./core/core.module";
import { PathUtils } from "./core/utils/path.utils";
import { FeaturesModule } from "./features/features.module";

@Module({
    imports: [
        CoreModule,
        FeaturesModule,
        ScheduleModule.forRoot(),
        ThrottlerModule.forRoot([
            {
                name: "short",
                ttl: 1000, // 生存时间（以毫秒为单位）： 1 second
                limit: 10 // ttl 内的最大请求数：每秒最多请求10次
            },
            {
                name: "medium",
                ttl: 10000,
                limit: 30
            },
            {
                name: "long",
                ttl: 60000,
                limit: 100
            }
        ]),
        // ServeStaticModule.forRoot(
        //     {
        //         rootPath: join(process.cwd(), "client/pc"), // 静态资源物理目录
        //         // serveRoot: "/", // 访问路径前缀
        //         exclude: ["/api/*", "/graphql/*", "/admin/*"],
        //         // 静态资源服务的底层选项，这些选项会透传给底层中间件，如 express-static
        //         serveStaticOptions: {
        //             fallthrough: true // 默认 true。当文件不存在时，不抛出 404 错误，返回 index.html。spa 应用必须设置为 true
        //         }
        //     },
        //     {...}
        // )
        // 动态模块方式注册，方便注入其他模块
        ServeStaticModule.forRootAsync({
            imports: [ConfigModule],
            inject: [ConfigService],
            useFactory: (_config: ConfigService) => {
                const clientAdminProjectDir = PathUtils.joinFs(STATIC_ASSETS_CLIENT_ROOT_DIR, STATIC_ADMIN_DIR);
                const clientPcProjectDir = PathUtils.joinFs(STATIC_ASSETS_CLIENT_ROOT_DIR, STATIC_PC_DIR);
                const clientMobileProjectDir = PathUtils.joinFs(STATIC_ASSETS_CLIENT_ROOT_DIR, STATIC_MOBILE_DIR);

                if (!fs.existsSync(clientAdminProjectDir)) fs.mkdirSync(clientAdminProjectDir, { recursive: true });
                if (!fs.existsSync(clientPcProjectDir)) fs.mkdirSync(clientPcProjectDir, { recursive: true });
                if (!fs.existsSync(clientMobileProjectDir)) fs.mkdirSync(clientMobileProjectDir, { recursive: true });

                Logger.log("📁 静态资源目录，客户端项目目录已创建完毕！", "ServeStaticModule");

                // 有个易错点：rootPath 的值不会出现在浏览器的请求路径中，它是服务器的物理路径，服务器域名就相当于该物理路径。
                // 比如设置 rootPath 为 /xxx，想获取物理路径下 /xxx/image/ikun.jpg 图片，浏览器访问的路径不是 http://localhost:8080/xxx/image/ikun.jpg。
                // 此时浏览器的域名就相当于 /xxx 目录，因此正确 URL 是 http://localhost:8080/image/ikun.jpg
                // 另外，serveRoot 的值才会出现在浏览器请求路径中
                // 例如：
                // rootPath: join(process.cwd(), "client"), serveRoot: "/static"，请求路径就是 http://localhost:8080/static/image/ikun.jpg

                // return IS_PROD_ENV ? [] : []; // 开发环境可能由Vite/Webpack Dev Server处理

                return [
                    {
                        rootPath: join(process.cwd(), clientAdminProjectDir, "dist"), // client/admin/dist 后台管理系统
                        serveRoot: "/admin",
                        exclude: ["/api/*", "/graphql/*"],
                        serveStaticOptions: {
                            fallthrough: true
                        }
                    },
                    {
                        rootPath: join(process.cwd(), clientPcProjectDir, "dist"), // client/pc/dist 前台PC应用
                        serveRoot: "/",
                        exclude: ["/api/*", "/graphql/*"],
                        serveStaticOptions: {
                            fallthrough: true
                        }
                    },
                    {
                        rootPath: join(process.cwd(), clientMobileProjectDir, "dist"), // client/h5/dist 前台H5应用
                        serveRoot: "/mobile",
                        exclude: ["/api/*", "/graphql/*"],
                        serveStaticOptions: {
                            fallthrough: true
                        }
                    }
                ];
            }
        })
    ],
    controllers: [AppController],
    providers: [
        AppService,
        {
            provide: APP_GUARD,
            useClass: ThrottlerGuard
        }
    ]
})
export class AppModule {}
